﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using AL.Doodled.Extensions.String;

namespace AL.Doodled.Compiling
{
    /// <summary>
    /// The WidgetCompiler handles instanciating of
    /// widget xml information.
    /// </summary>
    internal class WidgetCompiler
    {
        #region field
        private DoodledEngine engine;
        #endregion

        #region constructor
        public WidgetCompiler(DoodledEngine engine)
        {
            this.engine = engine;
        }
        #endregion

        #region methods
        /// <summary>
        /// Convert a Widget XElement into a Widget Instance.
        /// </summary>
        /// <param name="element">A XElement instance containing a widget xml element.</param>
        /// <returns></returns>
        public Widget Compile(XElement element)
        {
            Widget widget;
            Type widgetType = null;
            List<Widget> childs = new List<Widget>();
            Dictionary<string, string> attributes = new Dictionary<string, string>();
            Style style = new Style();

            foreach (string s in engine.TypePaths)
            {
                widgetType = Type.GetType(
                    s + element.Name.ToString().Capitalize(),
                    false);

                //If the type was found, we can exit the loop.
                if (widgetType != null)
                    break;
            }

            //Make sure the widget type was found.
            if (widgetType == null)
                throw new Exception(@"No type found for widget, please
make sure that you have entered the correct type for the widget and 
registered the type search path.");

            widget = (Widget)Activator.CreateInstance(widgetType);

            StyleState defaultState = new StyleState();

            if (element.Attribute("class") != null)
            {
                string klass = element.Attribute("class").Value;
                if (engine.WSRegister.IsClassRegistered(klass))
                    widget.Style = engine.WSRegister.GetStyleByClass(klass);
            }

            foreach (string key in widget.Style.GetDefaultState().AttributeKeys)
                defaultState.AddAttribute(key, style.GetDefaultState()[key]);

            if (element.Attribute("name") != null)
            {
                string name = element.Attribute("name").Value;
                if (engine.WSRegister.IsNameRegistered(name))
                    widget.Style = engine.WSRegister.GetStyleByName(name);
            }

            foreach (string key in widget.Style.GetDefaultState().AttributeKeys)
                defaultState.AddAttribute(key, style.GetDefaultState()[key]);

            if (element.Attribute("style") != null)
            {
                string styleData = element.Attribute("style").Value;
                foreach (var attribute in engine.Compiler.ExtractStyleAttributes(styleData))
                    defaultState.AddAttribute(attribute.Key, attribute.Value);
            }

            style.AlterState("default", defaultState);
            style.SetCurrentState("default");

            widget.Saturate(
                element.Attributes().ToDictionary(a => a.Name.ToString(), a => a.Value),
                string.Join("", from e in element.Nodes()
                                where e.NodeType ==
                                    System.Xml.XmlNodeType.Text
                                select ((XText)e).Value),
                     style);

            foreach (XElement ele in element.Elements())
                childs.Add(Compile(ele));
            foreach (Widget child in childs)
                child.Parent = widget;
            widget.Childs = childs.ToArray();

            return widget;
        }
        #endregion
    }
}
